package logger

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"time"
)

// Config 日志配置
type Config struct {
	Level      string `json:"level" yaml:"level"`           // 日志级别: debug, info, warn, error, dpanic, panic, fatal
	Filename   string `json:"filename" yaml:"filename"`     // 日志文件路径
	MaxSize    int    `json:"maxSize" yaml:"maxSize"`       // 每个日志文件的最大大小(MB)
	MaxBackups int    `json:"maxBackups" yaml:"maxBackups"` // 保留的旧日志文件最大数量
	MaxAge     int    `json:"maxAge" yaml:"maxAge"`         // 保留旧日志文件的最大天数
	Compress   bool   `json:"compress" yaml:"compress"`     // 是否压缩/归档旧日志文件
	Stdout     bool   `json:"stdout" yaml:"stdout"`         // 是否输出到标准输出
}

// Logger 封装zap.Logger
type Logger struct {
	*zap.Logger
}

// NewLogger 创建Logger实例
func NewLogger(config Config) (*Logger, error) {
	// 设置日志级别
	level := zap.NewAtomicLevel()
	if err := level.UnmarshalText([]byte(config.Level)); err != nil {
		return nil, err
	}

	// 编码器配置
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	// 设置日志输出
	var cores []zapcore.Core

	// 文件输出
	if config.Filename != "" {
		fileWriter := zapcore.AddSync(&lumberjack.Logger{
			Filename:   config.Filename,
			MaxSize:    config.MaxSize,
			MaxBackups: config.MaxBackups,
			MaxAge:     config.MaxAge,
			Compress:   config.Compress,
			LocalTime:  true,
		})
		fileCore := zapcore.NewCore(
			zapcore.NewJSONEncoder(encoderConfig),
			fileWriter,
			level,
		)
		cores = append(cores, fileCore)
	}

	// 标准输出
	if config.Stdout {
		stdoutCore := zapcore.NewCore(
			zapcore.NewConsoleEncoder(encoderConfig),
			zapcore.AddSync(os.Stdout),
			level,
		)
		cores = append(cores, stdoutCore)
	}

	// 如果没有配置任何输出，默认输出到标准输出
	if len(cores) == 0 {
		stdoutCore := zapcore.NewCore(
			zapcore.NewConsoleEncoder(encoderConfig),
			zapcore.AddSync(os.Stdout),
			level,
		)
		cores = append(cores, stdoutCore)
	}

	core := zapcore.NewTee(cores...)

	// 创建Logger
	logger := zap.New(core,
		zap.AddCaller(),
		zap.AddCallerSkip(1),
		zap.AddStacktrace(zapcore.ErrorLevel),
	)

	return &Logger{Logger: logger}, nil
}

// Sync 刷新缓冲区
func (l *Logger) Sync() {
	_ = l.Logger.Sync()
}

// WithFields 添加结构化字段
func (l *Logger) WithFields(fields map[string]interface{}) *Logger {
	zapFields := make([]zap.Field, 0, len(fields))
	for k, v := range fields {
		zapFields = append(zapFields, zap.Any(k, v))
	}
	return &Logger{Logger: l.Logger.With(zapFields...)}
}

// WithRequestID 添加请求ID字段
func (l *Logger) WithRequestID(requestID string) *Logger {
	return &Logger{Logger: l.Logger.With(zap.String("request_id", requestID))}
}

// WithDuration 添加耗时字段
func (l *Logger) WithDuration(d time.Duration) *Logger {
	return &Logger{Logger: l.Logger.With(zap.Duration("duration", d))}
}
